#ifndef _PILINK_CORE_H_
#define _PILINK_CORE_H_




/**************************************************************************************************
 *  
 *                            Structure of Pilink message:
 * 
 * ------------------------------------------------------------------------------------------------
 * Segment:  |  Header   | Sender id |  Type     |  Length   |   Data    |  Checksum  |   Tail    |
 * ------------------------------------------------------------------------------------------------
 * Data Type:|  uint16_t | uint8_t   |  uint16_t |  uint16_t  |  uint8_t  |  uint8_t   |  uint16_t |
 * ------------------------------------------------------------------------------------------------
 * Length:   |  2 Bytes  |  1 Byte   |  2 Byte   |  2 Byte    |  N Bytes  |   1 Byte   |  uint16_t |
 * ------------------------------------------------------------------------------------------------
 * 
 *  1. checksum is sum of Data
 *  2. N is indicated by Length 
 * 
 * ***********************************************************************************************/



#define PILINK_HEAD1   0xFA
#define PILINK_HEAD2   0xAA

#define PILINK_END1    0xFE
#define PILINK_END2    0xFD

#define PILINK_HANDLER_BUFFER_LENGTH  384


enum pilink_status_e{
    GSTATUS_IDLE = 0,
    GSTATUS_HEAD,
    GSTATUS_SENDER,
    GSTATUS_PORT1,
    GSTATUS_PORT2,
    GSTATUS_LEN1,
    GSTATUS_LEN2,
    GSTATUS_DATA,
    GSTATUS_CHECK,
    GSTATUS_END1,
    GSTATUS_END2,
};

struct pilink_handler_s{
    enum pilink_status_e status;
    
    unsigned char   sender;
    unsigned short  type;
    unsigned short  length;
    unsigned char   checksum;
    unsigned short  wptr;
    unsigned char   buf[PILINK_HANDLER_BUFFER_LENGTH];
    
};


#define PILINK_TRANSCEIVER_BUFFER_LENGTH  (PILINK_HANDLER_BUFFER_LENGTH+32)

struct pilink_transceiver_s;
typedef void (*pilink_transceiver_callback_t)(struct pilink_transceiver_s *xcev, unsigned short type, unsigned char *buf, int length);
struct pilink_channel_s{
    int    (*init)(struct pilink_channel_s *ch);
    int    (*deinit)(struct pilink_channel_s *ch);
    int    (*config)(struct pilink_channel_s *ch);
    int    (*recv)(struct pilink_channel_s *ch, unsigned char *buf, int len);
    int    (*send)(struct pilink_channel_s *ch, unsigned char *buf, int len);

    int     device;
    void   *priv_data;
};

struct pilink_transceiver_s{
    int    sender_id;
    struct pilink_handler_s handler;
    struct pilink_channel_s *channel;

    pilink_transceiver_callback_t msg_cb;
    
    char rxbuf[PILINK_TRANSCEIVER_BUFFER_LENGTH];
    unsigned char txbuf[PILINK_TRANSCEIVER_BUFFER_LENGTH];
};

#ifndef NULL
    #define NULL (0)
#endif   


#pragma pack(1)


struct pilink_string_s{
    unsigned long long timestamp;
    unsigned char len;
    char msg[PILINK_HANDLER_BUFFER_LENGTH / 4];
};

struct pilink_ack_s{
    unsigned long long timestamp;
    unsigned int  type;
    unsigned int  param[6];
};

struct pilink_terminal_data_s{
    unsigned long long timestamp;
    unsigned short cmd;
    unsigned short channel;
    unsigned short msg_len;
    char msg[128];
};

#pragma pack()


#ifdef __cplusplus
extern "C" {
#endif

void            pilink_handler_init(struct pilink_handler_s *handler);
int             pilink_handler_parse(struct pilink_handler_s *handler,unsigned char ch);
unsigned char   pilink_handler_calc_checksum(struct pilink_handler_s *handler);
unsigned char*  pilink_handler_get_data(struct pilink_handler_s *handler);
int             pilink_msg_pack(unsigned char *buffer, unsigned char sender, unsigned short type, unsigned char *dat, unsigned short len);

int             pilink_transceiver_init(struct pilink_transceiver_s *xceiver, int sender_id, struct pilink_channel_s *channel, pilink_transceiver_callback_t cb);
int             pilink_transceiver_config(struct pilink_transceiver_s *xceiver, void *cfg);
int             pilink_transceiver_send(struct pilink_transceiver_s *xceiver, unsigned short type, unsigned char *dat, unsigned short len);
int             pilink_transceiver_run(struct pilink_transceiver_s *xceiver);

int             pilink_string_set(struct pilink_string_s *str, char *s);

#ifdef __cplusplus
}
#endif

#define PILINK_CLASS_CORE             0x0000
#define PILINK_CLASS_PILOT            0x1000
#define PILINK_CLASS_CAMERA           0x2000
#define PILINK_CLASS_FILE             0x3000
#define PILINK_CLASS_BOOT             0x4000


#define PILINK_TYPE_FLOAT             (PILINK_CLASS_CORE + 0x001)
#define PILINK_TYPE_INT               (PILINK_CLASS_CORE + 0x002)
#define PILINK_TYPE_STRING            (PILINK_CLASS_CORE + 0x003)
#define PILINK_TYPE_TERMINAL          (PILINK_CLASS_CORE + 0x004)
#define PILINK_TYPE_ACK               (PILINK_CLASS_CORE + 0xFFF)

#endif